package com.qby.common.utils;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 二维码生成
 * @author: qiu bo yang
 * @create: 2020-03-12 10:02
 */
@Slf4j
public class QRCodeUtils {
    /**
     * 生成普通二维码
     *
     * @param text     二维码内容
     * @param width    二维码宽度
     * @param height   二维码高度
     * @param savePath 图片路径 例如 D:/picture/
     * @return filePath 返回文件地址
     */
    public static String generateQRCodeImage(String text, int width, int height, String savePath) {
        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
            //路径创建文件夹
            File Folder = new File(savePath);
            if (!Folder.exists()) {
                Folder.mkdirs();
            }
            String filePath = savePath + "/" + System.currentTimeMillis() + ".png";
            Path path = FileSystems.getDefault().getPath(filePath);
            MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
            log.info("二维码生成成功");
            return filePath;
        } catch (WriterException e) {
            log.info("二维码生成失败");
            e.printStackTrace();
        } catch (IOException e) {
            log.info("二维码生成失败");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 识别二维码内容
     *
     * @param file 二维码图片
     * @return text 返回二维码图片内容
     */
    public static String readQRCodeImage(File file) {
        String text = "";
        //读取二维码文件
        try {
            BufferedImage bufferedImage = ImageIO.read(file);
            MultiFormatReader formatReader = new MultiFormatReader();
            BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));
            //定义二维码参数
            Map hints = new HashMap();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            Result result = formatReader.decode(binaryBitmap, hints);
            //返回二维码内容信息
            text = result.getText();
            log.info("解析结果：{}", result.toString());
            log.info("二维码格式类型：{}", result.getBarcodeFormat());
            log.info("二维码文本内容：{}", result.getText());
            bufferedImage.flush();
        } catch (IOException e) {
            log.info("解析失败");
            e.printStackTrace();
        } catch (NotFoundException e) {
            log.info("解析失败");
            e.printStackTrace();
        }
        return text;
    }

    /**
     * 生成含有logo的二维码
     *
     * @param text     二维码内容
     * @param width    二维码宽度
     * @param height   二维码高度
     * @param savePath 保存路径  例如 D:/picture
     * @param logoPath logo地址  例如 D:/picture/logo.png
     * @return filePath 返回文件地址
     */
    public static String generateLogoQRCodeImage(String text, int width, int height, String savePath, String logoPath) {
        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            //内容编码格式
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            // 指定纠错等级
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            //设置二维码边的空度，非负数
            hints.put(EncodeHintType.MARGIN, 1);
            BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
            MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
            BufferedImage bufferedImage = LogoMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig),
                    new File(logoPath));
            //路径创建文件夹
            File Folder = new File(savePath);
            if (!Folder.exists()) {
                Folder.mkdirs();
            }
            String filePath = savePath + "/" + System.currentTimeMillis() + ".png";
            //输出带logo图片
            ImageIO.write(bufferedImage, "png", new File(filePath));
            log.info("二维码生成成功");
            return filePath;
        } catch (WriterException e) {
            log.info("二维码生成失败");
            e.printStackTrace();
        } catch (IOException e) {
            log.info("二维码生成失败");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 组合生成二维码和logo图片方法
     *
     * @param matrixImage 生成二维码
     * @param logoFile    logo图片文件
     * @return
     */
    private static BufferedImage LogoMatrix(BufferedImage matrixImage, File logoFile) {
        try {
            //读取二维码图片，并构建绘图对象
            Graphics2D g2 = matrixImage.createGraphics();
            int matrixWidth = matrixImage.getWidth();
            int matrixHeight = matrixImage.getHeight();
            //读取logo图片
            BufferedImage logo = ImageIO.read(logoFile);

            //开始绘制图片
            g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeight / 5 * 2, matrixWidth / 5, matrixHeight / 5, null);//绘制
            BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            // 设置笔画对象
            g2.setStroke(stroke);
            //指定弧度的圆角矩形
            RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth / 5 * 2, matrixHeight / 5 * 2, matrixWidth / 5, matrixHeight / 5, 20, 20);
            g2.setColor(Color.white);
            // 绘制圆弧矩形
            g2.draw(round);

            //设置logo 有一道灰色边框
            BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            // 设置笔画对象
            g2.setStroke(stroke2);
            RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth / 5 * 2 + 2, matrixHeight / 5 * 2 + 2, matrixWidth / 5 - 4, matrixHeight / 5 - 4, 20, 20);
            g2.setColor(new Color(128, 128, 128));
            // 绘制圆弧矩形
            g2.draw(round2);

            g2.dispose();
            matrixImage.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return matrixImage;
    }
}
